package com.xyxeshang.es.music.backend.service.impl;

import com.xyxeshang.es.music.backend.constant.ResultConstant;
import com.xyxeshang.es.music.backend.entity.*;
import com.xyxeshang.es.music.backend.exception.CustomException;
import com.xyxeshang.es.music.backend.mapper.*;
import com.xyxeshang.es.music.backend.service.AdminService;
import com.xyxeshang.es.music.backend.util.EsMusicUtil;
import com.xyxeshang.es.music.backend.util.EsRedisUtil;
import com.xyxeshang.es.music.backend.util.ResultUtil;
import org.apache.ibatis.jdbc.Null;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * @author xyx-Eshang
 */
@Service
@SuppressWarnings("all")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class AdminServiceImpl implements AdminService {

    @Resource
    private SongMapper songMapper;

    @Resource
    private SongCommentMapper songCommentMapper;

    @Resource
    private SongLikeMapper songLikeMapper;

    @Resource
    private AlbumMapper albumMapper;

    @Resource
    private ArtistMapper artistMapper;

    @Resource
    private SongArtistMapper songArtistMapper;

    /**
     * 每24h自动更新歌单
     */
    @PostConstruct
    public void beforeInit() throws InterruptedException {
        System.err.println("即将更新榜单数据");
        new Thread(() -> {
            Object lock = new Object();
            synchronized (lock) {
                try {
                    lock.wait(1000 * 5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                while (true) {
                    // 每过24h刷新一次榜单
                    refreshBillboard();
                    try {
                        lock.wait(1000 * 60 * 60 * 24);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "t0-postConstruct").start();
    }

    /**
     * 底层函数：保存歌曲信息
     *
     * @param song
     */
    private void baseSaveSong(Song song) {
        String songId = song.getSongId();
        //1. 歌曲song
        if (songMapper.getById(songId) == null) {
            songMapper.save(song);
        }
        //2. 专辑album
        String albumId = song.getAlbumId();
        if (albumMapper.getById(albumId) == null) {
            albumMapper.save(song.getAlbum());
        }
        //3. 作者artist：
        for (Artist artist : song.getArtistList()) {
            String artistId = artist.getArtistId();
            if (artistMapper.getById(artistId) == null) {
                artistMapper.save(artist);
            }
        }
        //4. songArtist：先判断原来数据库中是否有数据
        List<SongArtist> songArtistList = songArtistMapper.listBySongId(songId);
        //4-1. 有数据时，判断这首歌的作者是否变更
        if (songArtistList.size() != 0) {
            Set<String> oldArtistIdSet = new HashSet<>();
            for (SongArtist songArtist : songArtistList) {
                String artistId = songArtist.getArtistId();
                oldArtistIdSet.add(artistId);
            }
            for (Artist artist : song.getArtistList()) {
                String artistId = artist.getArtistId();
                oldArtistIdSet.add(artistId);
            }
            // 如果作者变更，删除原数据，重新新增
            if (oldArtistIdSet.size() != song.getArtistList().size()) {
                songArtistMapper.deleteBySongId(songId);
                for (Artist artist : song.getArtistList()) {
                    SongArtist songArtist = new SongArtist()
                            .setSongId(songId)
                            .setArtistId(artist.getArtistId());
                    songArtistMapper.save(songArtist);
                }
            }
        }
        //4-2. 无数据时，直接新增即可
        else {
            for (Artist artist : song.getArtistList()) {
                SongArtist songArtist = new SongArtist()
                        .setSongId(songId)
                        .setArtistId(artist.getArtistId());
                songArtistMapper.save(songArtist);
            }
        }
    }

    /**
     * 底层函数：刷新榜单
     *
     * @param EnglishType
     */
    private void baseRefreshBillboard(String EnglishType) throws CustomException {
        String ChineseType;
        if ("hot".contentEquals(EnglishType)) {
            ChineseType = "热门";
        } else if ("new".contentEquals(EnglishType)) {
            ChineseType = "新歌";
        } else if ("up".contentEquals(EnglishType)) {
            ChineseType = "飙升";
        } else if ("tikTok".contentEquals(EnglishType)) {
            ChineseType = "抖音排行";
        } else {
            throw new CustomException(ResultConstant.PARAMETER_IS_WRONG);
        }
        if ("hot".contentEquals(EnglishType)) {
            List<Song> songList = null;
            try {
//						//1. 更新之前，先保存数据：评论和点赞
//						System.err.println("正在持久化缓存中的数据...");
                List<Song> oldSongList = EsRedisUtil.getHotBillboard(-1);
//						if (oldSongList.size() == 0) {
//							System.out.println("初次使用，没有需要持久化的数据！");
//						} else {
//							for (Song song : oldSongList) {
//								String songId = song.getSongId();
//								//1-1. 评论
//								//1-1-1. 存储
//								List<SongComment> oldSongCommentList = song.getSongCommentList();
//								for (SongComment oldSongComment : oldSongCommentList) {
//									songCommentMapper.save(oldSongComment);
//								}
//								//1-1-2. 删除
//								EsRedisUtil.clearHotComment(songId);
//
//								//1-2. 点赞
//								//1-2-1. 存储
//								List<SongLike> oldSongLikeList = EsRedisUtil.getHotLike(songId);
//								for (SongLike oldSongLike : oldSongLikeList) {
//									songLikeMapper.save(oldSongLike);
//								}
//								//1-2-2. 删除
//								EsRedisUtil.clearHotLike(songId);
//							}
//							System.out.println("缓存数据持久化完毕！");
//						}

                // 2. 更新redis榜单数据
                System.err.println("正在更新热歌榜...");
                songList = EsMusicUtil.listFromBillboard("hot");

                // 2-1. 查出数据后，先删除
                EsRedisUtil.clearHotBillboard();
                // 2-2. 先更新榜单
                EsRedisUtil.setHotBillboard(songList);
//						// 2-3. 再更新热歌点赞和评论
//						for (Song song : songList) {
//							String songId = song.getSongId();
//							//2-3-1. 热歌点赞
//							List<SongLike> songLikeList = songLikeMapper.listBySongId(songId);
//							for (SongLike songLike : songLikeList) {
//								EsRedisUtil.addHotLike(songLike);
//							}
//							//2-3-2. 热歌评论
//							List<SongComment> songCommentList = songCommentMapper.listBySongId(songId);
//							for (SongComment songComment : songCommentList) {
//								EsRedisUtil.addHotComment(songComment);
//							}
//
//						}
                System.out.println("热歌榜数据已更新！");

                // 3. 更新redis中热门搜索数据，并将信息存储到MySQL中
                System.err.println("正在更新热搜数据...");
                // 3-1. 先删掉所有热搜数据
                for (Song song : oldSongList) {
                    String oldSongName = song.getSongName();
                    EsRedisUtil.clearHotSearch(oldSongName);
                }

                // 3-2. 获取新的热搜数据
                int listSize = songList.size();
                for (int count = 0; count < listSize; count++) {
                    Song song = songList.get(count);
                    String songName = song.getSongName();
                    List<Song> subSongList = EsRedisUtil.setHotSearch(songName);
                    for (Song subSong : subSongList) {
                        baseSaveSong(song);
                    }

                    System.out.println("热搜数据更新进度：(" + (count + 1) + " / " + listSize + ")（更新过程中，程序也可正常使用）");
                }
                // 4. 关闭定时器
                System.out.println("热搜数据已更新！");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.err.println("正在更新" + ChineseType + "榜...");
            List<Song> songList = null;
            try {
                songList = EsMusicUtil.listFromBillboard(EnglishType);
                // 1. 更新redis数据
                if ("new".contentEquals(EnglishType)) {
                    EsRedisUtil.clearNewBillboard();
                    EsRedisUtil.setNewBillboard(songList);
                } else if ("up".contentEquals(EnglishType)) {
                    EsRedisUtil.clearUpBillboard();
                    EsRedisUtil.setUpBillboard(songList);
                } else if ("tikTok".contentEquals(EnglishType)) {
                    EsRedisUtil.clearTikTokBillboard();
                    EsRedisUtil.setTikTokBillboard(songList);
                } else {
                    // 不可能是其他值
                }
                // 2. 存储song到MySQL中
                for (Song song : songList) {
                    baseSaveSong(song);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 3. 关闭定时器
            System.out.println(ChineseType + "榜数据已更新！");
        }
    }

    /**
     * 手动更新榜单
     *
     * @return
     */
    @Override
    public ResultUtil<Null> refreshBillboard() {
        try {
            // 开启4个线程分别刷新不同的榜单
            Thread t1 = new Thread(() -> {
                try {
                    baseRefreshBillboard("new");
                } catch (CustomException e) {
                    e.printStackTrace();
                }
            }, "t1-new");

            Thread t2 = new Thread(() -> {
                try {
                    baseRefreshBillboard("up");
                } catch (CustomException e) {
                    e.printStackTrace();
                }
            }, "t2-up");

            Thread t3 = new Thread(() -> {
                try {
                    baseRefreshBillboard("tikTok");
                } catch (CustomException e) {
                    e.printStackTrace();
                }
            }, "t3-tikTok");


            Thread t4 = new Thread(() -> {
                try {
                    baseRefreshBillboard("hot");
                } catch (CustomException e) {
                    e.printStackTrace();
                }
            }, "t4-hot");

            new Thread(() -> {
                t1.start();
                t2.start();
                t3.start();
                t4.start();

                try {
                    t1.join();
                    t2.join();
                    t3.join();
                    t4.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.err.println("所有榜单数据更新完毕！");
            }, "t0-main").start();
            return new ResultUtil<>();
        } catch (Exception e) {
            return new ResultUtil<>(e);
        }
    }
}
